using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Text;
using System.Windows.Forms;

using Tino.Controls;
using Tino.Core;

namespace Tino
{
    public partial class MainForm : Form
    {
        WelcomePanel welcome;

        public MainForm()
        {
            InitializeComponent();

            SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            SetStyle(ControlStyles.DoubleBuffer, true);
            SetStyle(ControlStyles.EnableNotifyMessage, false);
            SetStyle(ControlStyles.UserPaint, true);

            restoreGlobals();

            // Si show welcome ou, not show welcome but without any previous file opened, then ShowWelcome screen
            if (Globals.Get().ShowWelcome || (!Globals.Get().ShowWelcome && Globals.Get().LastOpenedFile == ""))
                showWelcome();
            else
                Open(Globals.Get().LastOpenedFile);
        }

        #region Form parameters members

        bool saveGlobals()
        {
            Globals g = Globals.Get();
            g.X = Location.X;
            g.Y = Location.Y;
            g.Width = Size.Width;
            g.Height = Size.Height;
            g.VerticalSplit = mainSplitContainer.SplitterDistance;
            g.HorizontalSplit = entrySplitContainer.SplitterDistance;

            try
            {
                g.Save();
                return true;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }
        }

        void restoreGlobals()
        {
            Globals g = null;
            try
            {
                g = Globals.Get();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            try
            {
                Location = new Point(g.X, g.Y);
                Size = new Size(g.Width, g.Height);
                mainSplitContainer.SplitterDistance = g.VerticalSplit;
                entrySplitContainer.SplitterDistance = g.HorizontalSplit;

                // Word wrap stuff ...
                entryContentTextBox.WordWrap = g.WordWrap;
                wordWrapToolStripMenuItem.Checked = g.WordWrap;
            }
            catch (Exception)
            {
                MessageBox.Show("I couldn't restore saved parameters, but it's ok, Tino will work anyway!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }

        #endregion

        void showWelcome()
        {
            mainSplitContainer.Visible = false;
            welcome = new WelcomePanel();
            welcome.Dock = DockStyle.Fill;
            Controls.Add(welcome);

            controlsEnableStatus(false);
        }

        void hideWelcome()
        {
            if (welcome != null)
            {
                welcome.Visible = false;
                welcome.Dispose();
            }

            mainSplitContainer.Visible = true;
            entryContentTable.Visible = false;

            controlsEnableStatus(true);
        }

        void controlsEnableStatus(bool enable)
        {
            administrateTagsToolStripMenuItem.Enabled = enable;
            adminTagsToolStripButton.Enabled = enable;
            addEntryToolStripButton.Enabled = enable;
            addItemToolStripMenuItem.Enabled = enable;
            showAllToolStripButton.Enabled = enable;
            showAllToolStripMenuItem.Enabled = enable;
        }

        public void New()
        {
            if (Globals.Get().LastSeenDirectory != "")
                saveFileDialog.InitialDirectory = Globals.Get().LastSeenDirectory;

            if (saveFileDialog.ShowDialog() == DialogResult.OK)
            {
                CreateNewDBCommand command = new CreateNewDBCommand();
                string path = saveFileDialog.FileName;
                FileInfo f = new FileInfo(path);
                if (f.Extension == "") path = path + ".tdt";
                
                if (command.Create(path))
                {
                    Open(path);
                }
            }
        }

        public void Open()
        {
            if (Globals.Get().LastSeenDirectory != "")
                openFileDialog.InitialDirectory = Globals.Get().LastSeenDirectory;

            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                FileInfo f = new FileInfo(openFileDialog.FileName);
                Globals.Get().LastSeenDirectory = f.DirectoryName;
                Open(openFileDialog.FileName);
            }
        }

        public void Open(string path)
        {
            Context.Current.ConnectionString = SqliteConnectionBuilder.GetConnectionString(path);
            CheckDBValidityCommand command = new CheckDBValidityCommand();
            if (command.IsValid())
            {
                // Save this opened file
                Globals.Get().LastOpenedFile = path;

                // Update List with tags
                loadTags();

                // Final UI treatment
                hideWelcome();
            }
            else Context.Current.ConnectionString = string.Empty;
        }

        void quit()
        {
            Close();
            Dispose();
        }

        #region Members related to Tags

        void loadTags()
        {
            GetTagsCommand commandTags = new GetTagsCommand(tagsList);
            commandTags.Execute();
            
            RefreshAutoCompletionSearchBox commandSearch = new RefreshAutoCompletionSearchBox(filterTagTextBox);
            commandSearch.Execute();
        }

        void administrateTags()
        {
            TagsAdministrationForm admin = new TagsAdministrationForm();
            if (admin.ShowDialog() == DialogResult.OK)
            {
                // Remove deleted tags from the list, and from the input if they were checked.
                foreach (TagsListItem item in admin.DeletedItems)
                {
                    int idx = -1;
                    for (int i = 0; i < tagsList.Items.Count; i++)
                    {
                        if (((TagsListItem)tagsList.Items[i]).Name == item.Name)
                        {
                            idx = i;
                            break;
                        }
                    }
                    
                    if (idx > -1)
                        tagsList.Items.RemoveAt(idx);
                }

                // Add created tags to the list
                foreach (TagsListItem item in admin.AddedItems)
                {
                    tagsList.Items.Add(item);
                }

                // Refresh autocomplete source
                RefreshAutoCompletionSearchBox commandSearch = new RefreshAutoCompletionSearchBox(filterTagTextBox);
                commandSearch.Execute();
            }
            admin.Dispose();
        }

        int[] getSelectedTagsIDs()
        {
            int[] ids = new int[tagsList.CheckedIndices.Count];
            for (int i = 0; i < tagsList.CheckedIndices.Count; i++)
                ids[i] = ((TagsListItem)tagsList.CheckedItems[i]).ID;

            return ids;

        }

        TagsListItemsCollection getSelectedTagsListItem()
        {
            TagsListItemsCollection l = new TagsListItemsCollection();
            foreach (TagsListItem item in tagsList.CheckedItems)
                l.Add(item);
            return l;
        }

        void clearSelection()
        {
            // Deselect all checked items
            entriesList.BeginUpdate();
            for (int i = 0; i < tagsList.Items.Count; i++)
                tagsList.SetItemChecked(i, false);
            entriesList.EndUpdate();
            entriesList.SelectedIndex = -1;
            entriesList.Clear();
            // Hide the preview pane
            entryContentTable.Visible = false;
        }

        #endregion

        #region Members related to Entries

        void loadEntries()
        {
            loadEntries(false);
        }
        
        void loadEntries(bool all)
        {
            int[] selectedTagsIDs = getSelectedTagsListItem().ToArray();

            if (selectedTagsIDs.Length > 0 || all)
            {
                // Load entries only if a tag at least is selected
                GetEntriesCommand command = new GetEntriesCommand(entriesList, selectedTagsIDs);
                command.Execute();

                // Show & clear the preview pane
                resetEntryPreviewPane();
                entryContentTable.Visible = true;
                // Deselect any selection ...
                entriesList.SelectedIndex = -1;
            }
            else
            {
                entriesList.SelectedIndex = -1;
                entriesList.Clear();
                // Hide the preview pane
                entryContentTable.Visible = false;
            }
        }

        void resetEntryPreviewPane()
        {
            entryTitleTextBox.Text = "";
            entryContentTextBox.Rtf = "";
            entryTagsTextBox.Text = "";
        }

        /// <summary>
        /// Once an entry is selected, load synchronously the content into 
        /// appropriates fields
        /// </summary>
        void loadEntry(int entryID)
        {
            LoadEntryCommand command = new LoadEntryCommand(entryID, entryTitleTextBox, 
                entryContentTextBox, entryTagsTextBox);

            command.Execute();
        }

        void addEntry()
        {
            EntryEditorForm editor = new EntryEditorForm(entryImagesList);
            editor.PreFillTagsSelection(getSelectedTagsListItem());
            if (editor.ShowDialog() == DialogResult.OK)
            {
                Entry e = new Entry();
                int newEntryID = -1;
                try
                {
                    newEntryID = e.AddEntry(editor.Title, editor.Content, editor.ImageIndex, editor.TagsIDs);
                    // Refresh the selectioned entries
                    loadEntries();                    
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                finally
                {
                    editor.Dispose();
                }
            }
            editor.Dispose();
        }

        void editEntry()
        {
            if (entriesList.SelectedIndex > -1)
            {
                int entryID = entriesList.SelectedEntryID;
                EntryEditorForm editor = new EntryEditorForm(entryID, entryImagesList);
                if (editor.ShowDialog() == DialogResult.OK)
                {
                    Entry e = new Entry();
                    try
                    {
                        e.UpdateEntry(entryID, editor.Title, editor.Content, editor.ImageIndex, editor.TagsIDs);
                        // Redraw item
                        entriesList.Redraw(entriesList.SelectedIndex, editor.ImageIndex, editor.Title);
                        // Reload entry preview pane
                        loadEntry(entryID);
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                    finally
                    {
                        editor.Dispose();
                    }
                }
                editor.Dispose();
            }
        }

        void setIcon()
        {
            IconPickerForm iconPicker = new IconPickerForm(entryImagesList);
            if (iconPicker.ShowDialog() == DialogResult.OK)
            {
                if (entriesList.SelectedEntryID > -1)
                {
                    Entry e = new Entry();
                    try
                    {
                        e.UpdateEntryImageIndex(entriesList.SelectedEntryID, iconPicker.SelectedImageIndex);
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }

                    // Redraw this item
                    entriesList.Redraw(entriesList.SelectedIndex, iconPicker.SelectedImageIndex);
                }
            }
            iconPicker.Dispose();
        }

        void deleteEntry()
        {
            if (entriesList.SelectedEntryID > -1)
            {
                string msg = "Are you sure you want to delete this item?";
                if (MessageBox.Show(msg, "Tino", MessageBoxButtons.OKCancel, MessageBoxIcon.Question)
                    == DialogResult.OK)
                {
                    int entryID = entriesList.SelectedEntryID;
                    Entry e = new Entry();
                    try
                    {
                        e.DeleteEntry(entryID);
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }

                    // Change the selection to -1 (if exists of course)
                    int idx = entriesList.SelectedIndex;
                    entriesList.Remove(idx);

                    idx = (idx == 0 ? idx : idx - 1);
                    if (entriesList.Count == 0)
                    {
                        idx = -1;
                        // Hide preview pane
                        resetEntryPreviewPane();
                    }

                    entriesList.SelectedIndex = idx;
                }
            }
        }

        #endregion

        #region Form event handlers

        void MainForm_Activated(object sender, EventArgs e)
        {
            Application.AddMessageFilter(entryContentTextBox);
        }

        void MainForm_Deactivate(object sender, EventArgs e)
        {
            Application.RemoveMessageFilter(entryContentTextBox);
        }

        void MainForm_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Control && e.KeyCode == Keys.N)
                New();

            if (e.Control && e.KeyCode == Keys.O)
                Open();

            if (e.Control && e.KeyCode == Keys.Q)
                quit();

            if (e.Control && e.KeyCode == Keys.T)
                administrateTags();

            if (e.Control && e.KeyCode == Keys.X)
                clearSelection();

            if (e.Control && e.KeyCode == Keys.E)
                addEntry();

            if (e.Control && e.KeyCode == Keys.A)
                loadEntries(true);
        }

        void mainForm_Closing(object sender, FormClosingEventArgs e)
        {
            saveGlobals();
        }

        #region ToolStripMenu items

        void newToolStripMenuItem_Click(object sender, EventArgs e)
        {
            New();
        }

        void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Open();
        }

        void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            quit();
        }

        void administrateTagsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            administrateTags();
        }

        void clearSelectionToolStripMenuItem_Click(object sender, EventArgs e)
        {
            clearSelection();
        }

        void editItemToolStripMenuItem_Click(object sender, EventArgs e)
        {
            editEntry();
        }

        void removeItemToolStripMenuItem_Click(object sender, EventArgs e)
        {
            deleteEntry();
        }

        void addItemToolStripMenuItem_Click(object sender, EventArgs e)
        {
            addEntry();
        }

        void pickIconToolStripMenuItem_Click(object sender, EventArgs e)
        {
            setIcon();
        }

        void showAllItemsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            loadEntries(true);
        }

        void preferencesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            PreferencesForm pref = new PreferencesForm();
            pref.ShowDialog();
            pref.Dispose();
        }

        void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AboutForm about = new AboutForm();
            about.ShowDialog();
            about.Dispose();
        }

        #endregion

        #region ToolStripButton items

        void newToolStripButton_Click(object sender, EventArgs e)
        {
            New();
        }

        void openToolStripButton_Click(object sender, EventArgs e)
        {
            Open();
        }

        void adminTagsToolStripButton_Click(object sender, EventArgs e)
        {
            administrateTags();
        }

        void addEntryToolStripButton_Click(object sender, EventArgs e)
        {
            addEntry();
        }

        void editItemToolStripButton_Click(object sender, EventArgs e)
        {
            editEntry();
        }

        void removeEntryToolStripButton_Click(object sender, EventArgs e)
        {
            deleteEntry();
        }

        void pickIconToolStripButton_Click(object sender, EventArgs e)
        {
            setIcon();
        }

        void showAllToolStripButton_Click(object sender, EventArgs e)
        {
            loadEntries(true);
        }

        void clearSelectionToolStripButton_Click(object sender, EventArgs e)
        {
            clearSelection();
        }

        #endregion

        void filterTagTextBox_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Return)
            {
                TextBox tb = (TextBox)sender;
                for (int i = 0; i < tagsList.Items.Count; i++)
                {
                    TagsListItem item = (TagsListItem)tagsList.Items[i];
                    if (item.Name == tb.Text)
                    {
                        // Invert the check status and select the item (so that necessary events are triggered)
                        tagsList.SetItemChecked(i, (!tagsList.GetItemChecked(i)));
                        tagsList.SetSelected(i, true);
                        break;
                    }
                }
                tb.Text = "";
            }
        }

        void tagsList_SelectedIndexChanged(object sender, EventArgs e)
        {
            loadEntries();
        }

        void tagsListAdministrateToolStripMenuItem_Click(object sender, EventArgs e)
        {
            administrateTags();
        }

        void entriesList_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                int idx = entriesList.IndexAt(e.Location);
                if (idx > -1)
                {
                    entriesListEditToolStripMenuItem.Visible = true;
                    entriesListChooseIconToolStripMenuItem.Visible = true;
                    entriesListDeleteToolStripMenuItem.Visible = true;
                    entriesListToolStripSeparator.Visible = true;
                    entriesList.SelectedIndex = idx;
                }
                else
                {
                    entriesListEditToolStripMenuItem.Visible = false;
                    entriesListChooseIconToolStripMenuItem.Visible = false;
                    entriesListDeleteToolStripMenuItem.Visible = false;
                    entriesListToolStripSeparator.Visible = false;
                    entriesList.SelectedIndex = -1;
                }
            }
        }

        void entriesList_DoubleClick(object sender, EventArgs e)
        {
            editEntry();
        }

        void entriesListEditToolStripMenuItem_Click(object sender, EventArgs e)
        {
            editEntry();
        }

        void entriesListChooseIconToolStripMenuItem_Click(object sender, EventArgs e)
        {
            setIcon();
        }

        void entriesListDeleteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            deleteEntry();
        }

        void entriesListAddToolStripMenuItem_Click(object sender, EventArgs e)
        {
            addEntry();
        }

        void entriesList_SelectedEntryChanged(object sender, SelectedEntryChangedEventArgs e)
        {
            if (e.SelectedEntryIndex > -1)
                loadEntry(e.SelectedEntryID);

            // Handle controls enable status
            editItemToolStripMenuItem.Enabled = (e.SelectedEntryIndex > -1);
            editItemToolStripButton.Enabled = (e.SelectedEntryIndex > -1);
            removeEntryToolStripButton.Enabled = (e.SelectedEntryIndex > -1);
            removeItemToolStripMenuItem.Enabled = (e.SelectedEntryIndex > -1);
            pickIconToolStripMenuItem.Enabled = (e.SelectedEntryIndex > -1);
        }

        void entryContent_LinkClicked(object sender, LinkClickedEventArgs e)
        {
            string target = e.LinkText;
            if (target != null && target.StartsWith("http"))
            {
                System.Diagnostics.Process.Start(target);
            }
        }

        void entryContentCopyToolStripMenuItem_Click(object sender, EventArgs e)
        {
            entryContentTextBox.Copy();
        }

        void entryContentSelectAllToolStripMenuItem_Click(object sender, EventArgs e)
        {
            entryContentTextBox.SelectAll();
        }

        void wordWrapToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ToolStripMenuItem menu = (ToolStripMenuItem)sender;
            menu.Checked = !menu.Checked;
            entryContentTextBox.WordWrap = !entryContentTextBox.WordWrap;
            // Save this new settings
            Globals.Get().WordWrap = !Globals.Get().WordWrap;
        }

        #endregion
    }
}